home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / sonido / mod-0.000 / mod-0 / mod / options.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-15  |  11.1 KB  |  548 lines

  1. /*
  2.  *  options.c - Handles commandline options and selection of next module.
  3.  *
  4.  *  (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <time.h>
  11. #include <unistd.h>
  12. #include <fcntl.h>
  13. #include <limits.h>
  14.  
  15. #include "mod.h"
  16.  
  17. extern struct mod_info M;
  18. extern char workdir[PATH_MAX+1];
  19. extern struct mod_file *files;
  20. extern int nr_visible_voices;
  21.  
  22. struct options opt, default_opt;
  23. int nr_songs;                  /* Nr of songs specified */
  24. short *songs;           /* Starting pos in argv for the songs */
  25. short *song_sequence;   /* Order of the songs (if played) */
  26.  
  27. char **av;              /* Local pointer to argv */
  28. int ac;                 /* Local copy of argc    */
  29.  
  30. char background=0, totallyQ=0;
  31.  
  32.  
  33. void init_options(int argc, char *argv[])
  34. {
  35.     int fd;
  36.     char *env;
  37.     char buf[2048], *env_av[80];  /* Should be enough */
  38.     int env_ac, env_pos, buf_pos;
  39.     
  40.     nr_songs=0;
  41.  
  42.     bzero((void *)&default_opt, sizeof(struct options));
  43.     default_opt.max_lines=4711;   /* As many as possible   */
  44.     default_opt.active_voices=-1; /* All voices active     */
  45.     default_opt.maxtime=0;        /* No maxtime by default */
  46.  
  47.     default_opt.tempo=125;        /* PAL-tempo             */
  48.     default_opt.speed=6;
  49.  
  50.     default_opt.speed0stop=1;     /* PT3.0 compatability         */
  51.     default_opt.click_removal=0;  /* Clickremoval off by default */
  52.     default_opt.low_note=0;       /* Let patternloader set these */
  53.     default_opt.high_note=0;
  54.  
  55.     default_opt.loop_module=0;    /* No forced looping by default    */
  56.     default_opt.break_loops=-1;   /* Set to default if not specified */
  57.     default_opt.auto_next=-1;     /* Set to default if not specified */
  58.  
  59.     default_opt.voice_detail=0;   /* Default to not changing it */
  60.  
  61.     /* Check validity and set the "always global" options. First check
  62.      * the environment-variable, then the commandline.
  63.      */
  64.  
  65.     /* Check environment */
  66.     if((env=getenv(ENV_VAR_NAME))) {
  67.     if(env[0]) {
  68.         if(env[0] != '-')
  69.         error("Environment-variable " ENV_VAR_NAME
  70.               " must begin with a hyphen.\n");
  71.         env_pos=env_ac=0;
  72.         strcpy(buf, argv[0]);
  73.         buf_pos=strlen(buf)+1;
  74.  
  75.         /* Build the argument-array */
  76.         while(env[env_pos]) {
  77.         env_av[++env_ac]=&buf[buf_pos];
  78.         while(env[env_pos] && env[env_pos] != ' ' &&
  79.               env[env_pos] != '\t')
  80.             buf[buf_pos++]=env[env_pos++];
  81.         buf[buf_pos++]=0;
  82.         
  83.         while(env[env_pos] && (env[env_pos] == ' ' ||
  84.                        env[env_pos] == '\t'))
  85.             env_pos++;
  86.         }
  87.         av=env_av;
  88.         ac=++env_ac;
  89.         check_options(1); /* Parse, but abort at the first filename */
  90.         opt=default_opt;
  91.         parse_options(0);
  92.         default_opt=opt;
  93.     }
  94.     }
  95.  
  96.     /* These must allocated before check_options(0) is called */
  97.     songs=(short *)malloc(argc*sizeof(short));
  98.     song_sequence=(short *)malloc(argc*sizeof(short));
  99.  
  100.     /* Check commandline */
  101.     av=argv;
  102.     ac=argc;
  103.     check_options(0);
  104.     
  105.     if(background && default_opt.verbose)
  106.     error("Can't put a verbose session in the background.\n");
  107.     
  108.     if(default_opt.quiet && default_opt.verbose)
  109.     error("Quiet and verbose can't be used together.\n");
  110.     
  111.     opt=default_opt;
  112.     parse_options(0);
  113.     default_opt=opt;
  114.     
  115.     /* Turn on interactive mode if nothing else is specified */
  116.     if(!default_opt.verbose && !default_opt.quiet)
  117.     default_opt.interactive=1;
  118.  
  119.     /* Set defaults that depend on opt.play_list */
  120.     if(nr_songs < 1) {
  121.     default_opt.play_list=0;
  122.     if(default_opt.break_loops < 0)
  123.         default_opt.break_loops=0;
  124.     if(default_opt.auto_next < 0)
  125.         default_opt.auto_next=0;
  126.     opt=default_opt;
  127.     init_dir(workdir);
  128.     }
  129.     else {
  130.     default_opt.play_list=1;
  131.     if(default_opt.break_loops < 0)
  132.         default_opt.break_loops=1;
  133.     if(default_opt.auto_next < 0)
  134.         default_opt.auto_next=1;
  135.  
  136.     opt=default_opt;
  137.     init_playsequence();
  138.     list_to_files();
  139.     }
  140.  
  141.     if(default_opt.loop_module)    /* Loop as composer intended */
  142.     default_opt.break_loops=0;
  143.  
  144.     /* Rediect output if needed */
  145.     if(totallyQ || background) {
  146.     fd=open("/dev/null", O_RDWR, 0);
  147.     dup2(fd, STDIN_FILENO);
  148.     dup2(fd, STDOUT_FILENO);
  149.     dup2(fd, STDERR_FILENO);
  150.     close(fd);
  151.     }
  152.  
  153.     /* Detach if needed */
  154.     if(background) {
  155.     switch(fork()) {
  156.       case -1:
  157.         error("fork() failed.\n");
  158.       case 0:
  159.         write_pid(getpid());
  160.         break;
  161.       default:
  162.         exit(0);
  163.     }
  164.     }
  165.     opt=default_opt;
  166. }
  167.  
  168.  
  169. void check_options(char no_files)
  170. {
  171.     char next, tmp;
  172.     char *s;
  173.     int index=1;
  174.  
  175.     while(index < ac) {
  176.     while(index < ac) {
  177.         s=av[index];
  178.         if(*s == '-') {
  179.         s++;
  180.         next=0;
  181.         while(*s && !next) {
  182.             switch(*s) {
  183.               case 'a':
  184.             default_opt.auto_next=1;
  185.             break;
  186.               case 'A':
  187.             default_opt.auto_next=0;
  188.             break;
  189.               case 'b':
  190.             default_opt.break_loops=1;
  191.             break;
  192.               case 'B':
  193.             default_opt.break_loops=0;
  194.             break;
  195.               case 'C':
  196.             default_opt.replay_forever=1;
  197.             break;
  198.               case '?':
  199.               case 'h':
  200.             print_helptext(av[0]);
  201.             exit(0);
  202.             break;
  203.               case 'L':
  204.             default_opt.loop_module=1;
  205.             break;
  206.               case 'n':
  207.             default_opt.noscroll=1;
  208.             break;
  209.               case 'Q':
  210.             totallyQ=1;
  211.             /* Fall through to 'q' */
  212.               case 'q':
  213.             default_opt.quiet=1;
  214.             break;
  215.               case 'r':
  216.             default_opt.random_mode=1;
  217.             break;
  218.               case 'v':
  219.             default_opt.verbose++;
  220.             break;
  221.             
  222.               case 'z':
  223.             background=1;
  224.             default_opt.quiet=1;
  225.             break;
  226.  
  227.               case 'k':
  228.             error("Option '-k' must be the only argument.\n");
  229.             break;
  230.                   
  231.               case 'M':
  232.               case 'N':
  233.               case 'o':
  234.               case 'O':
  235.               case 'P':
  236.               case 'T':
  237.               case '0':
  238.               case '5':
  239.               case '6':
  240.             break;
  241.  
  242.               /* Parsed numerical arguments */
  243.               case 'l':
  244.             tmp=*s;
  245.             if(!getarg(&s, &index))
  246.                 goto horrible_goto;
  247.             next=1;
  248.             default_opt.max_lines=MAX(atoi(s), 1);
  249.             break;
  250.               case 'x':
  251.             tmp=*s;
  252.             if(!getarg(&s, &index))
  253.                 goto horrible_goto;
  254.             next=1;
  255.             break;
  256.  
  257.               /* Parsed alphanumerical arguments */
  258.               case 'D':
  259.             tmp=*s;
  260.             getarg(&s, &index);
  261.             next=1;
  262.             if(chdir(s))
  263.                 error("No such directory.\n");
  264.             getcwd(workdir, PATH_MAX);
  265.             break;
  266.  
  267.               /* Numerical arguments */
  268.               case 'c':
  269.               case 'm':
  270.               case 'p':
  271.               case 's':
  272.               case 't':
  273.             tmp=*s;
  274.             if(!getarg(&s, &index)) {
  275.               horrible_goto:
  276.                 error("%s: option -%c requires a (positive)"
  277.                    " numerical argument\n", av[0], tmp);
  278.             }
  279.             next=1;
  280.             break;
  281.  
  282.                       /* Alphanumerical arguments */
  283.               case 'f':
  284.             getarg(&s, &index);
  285.             next=1;
  286.             break;
  287.  
  288.               default:
  289.             error("%s: Unknown option -- %c\n", av[0], *s);
  290.             break;
  291.             }
  292.             s++;
  293.         }
  294.         index++;
  295.         }
  296.         else {
  297.         if(no_files) /* Abort after a file is found if no_files */
  298.             return;
  299.  
  300.         songs[nr_songs++]=index;
  301.         index++;
  302.         break;
  303.         }
  304.     }
  305.     }
  306. }
  307.  
  308.  
  309. /* Parse options */
  310.  
  311. void parse_options(int index)
  312. {
  313.     char next;
  314.     char *s;
  315.  
  316.     index++; /* Skip the filename */
  317.     
  318.     for(;;) {
  319.     s=av[index];
  320.     if(*s == '-') {
  321.         s++;
  322.         next=0;
  323.         while(*s && !next) {
  324.         switch(*s) {
  325.  
  326.             /* These needs no further processing */
  327.  
  328.           case 'a': case 'A': case 'b': case 'B':
  329.           case 'C': case '?': case 'h': case 'L':
  330.           case 'n': case 'q': case 'Q': case 'r': case 'v': case 'z':
  331.             break;
  332.  
  333.           case 'D':
  334.           case 'l':
  335.             getarg(&s, &index);
  336.             next=1;
  337.             break;
  338.  
  339.             /* These take no arguments */
  340.             
  341.           case 'M':
  342.             opt.mono=1;
  343.             break;
  344.           case 'N':
  345.             opt.ntsc_samples=1;
  346.             break;
  347.           case 'o':
  348.             opt.low_note=BASE_NOTE+3*12;
  349.             opt.high_note=BASE_NOTE+6*12-1;
  350.             break;
  351.           case 'O':
  352.             opt.low_note=BASE_NOTE+0*12;
  353.             opt.high_note=BASE_NOTE+NR_OCTAVES*12-1;
  354.             break;
  355.           case 'P':
  356.             opt.ntsc_samples=0;
  357.             break;
  358.           case 'T':
  359.             opt.tolerant=1;
  360.             break;
  361.           case '0':
  362.             opt.speed0stop=0;
  363.             break;
  364.           case '5':
  365.             opt.tempo=125; /* 50 Hz (125 BPM) -> 2.000/100 s */
  366.             opt.nobpm=1;
  367.             break;
  368.           case '6':
  369.             opt.tempo=150; /* 60 Hz (150 BPM) -> 1.667/100 s */
  370.             opt.nobpm=1;
  371.             break;
  372.             
  373.             /* These take arguments */
  374.             
  375.           case 'c':
  376.             getarg(&s, &index);
  377.             next=1;
  378.             opt.click_removal=atoi(s);
  379.             break;
  380.           case 'f':
  381.             getarg(&s, &index);
  382.             if(!strcmp(s, "mod"))
  383.             opt.format=MODFORMAT_MOD;
  384.             else if(!strcmp(s, "ult"))
  385.             opt.format=MODFORMAT_ULT;
  386.             else if(!strcmp(s, "mtm"))
  387.             opt.format=MODFORMAT_MTM;
  388.             else if(!strcmp(s, "s3m"))
  389.             opt.format=MODFORMAT_S3M;
  390.             else
  391.             info("Unknown format '%s' specified, "
  392.                  "option ignored.\n", s);
  393.             next=1;
  394.             break;
  395.           case 'm':
  396.             getarg(&s, &index);
  397.             next=1;
  398.             opt.maxtime=MAX(atoi(s), 1);
  399.             break;
  400.           case 'p':
  401.             getarg(&s, &index);
  402.             next=1;
  403.             opt.start_pos=MAX(atoi(s), 0);
  404.             break;
  405.           case 's':
  406.             getarg(&s, &index);
  407.             next=1;
  408.             opt.speed=MAX(atoi(s), 1);
  409.             break;
  410.           case 't':
  411.             getarg(&s, &index);
  412.             next=1;
  413.             opt.tempo=MIN(MAX(atoi(s), 32), 255);
  414.             break;
  415.           case 'x':
  416.             getarg(&s, &index);
  417.             next=1;
  418.             opt.voice_detail=MAX(1, MIN(3, atoi(s)));
  419.             break;
  420.  
  421.           default:
  422.             error("Internal error (unknown option).\n");
  423.         }
  424.         s++;
  425.         }
  426.         index++;
  427.     }
  428.     else
  429.         return; /* No more options */
  430.     }
  431.     error("Never reached\n");
  432. }
  433.  
  434.  
  435. /* This is rather pointless as we are about to exit() anyways... */
  436.  
  437. void cleanup_options(void)
  438. {
  439.     free(songs);
  440.     free(song_sequence);
  441. }
  442.  
  443.  
  444. /* Sets *s to the start of the argument. Returns true if the first character
  445.  * of the argument is a digit.
  446.  */
  447. int getarg(char **s, int *index)
  448. {
  449.     *s=*s+1;
  450.     if(!**s) {
  451.     *index=*index+1;
  452.     if(*index >= ac)
  453.         error("%s: Missing argument for option "
  454.           "-- %c\n", av[0], *(*s-1));
  455.     *s=av[*index];
  456.     }
  457.     
  458.     return (**s >= '0' && **s <= '9');
  459. }
  460.  
  461.  
  462. /* Selects next module by parsing it's options and setting the filename */
  463.  
  464. void get_module(int nr)
  465. {
  466.     int idx;
  467.  
  468.     opt=default_opt;
  469.     if(opt.play_list) {
  470.     idx=songs[song_sequence[nr]];
  471.     strcpy(M.real_filename, av[idx]); /* Set filename */
  472.     parse_options(idx); 
  473.     }
  474.     else {
  475.     strcpy(M.real_filename, files[nr].name);
  476.     }
  477. }
  478.  
  479. /* Returns the filename with path removed (sequenced order). Used to
  480.  * print current modulename on the screen.
  481.  */
  482.  
  483. char *get_modulename(int nr)
  484. {
  485.     static char buf[PATH_MAX+1];
  486.     int i;
  487.  
  488.     if(opt.play_list)
  489.     strcpy(buf, av[songs[song_sequence[nr]]]);
  490.     else
  491.     strcpy(buf, files[nr].name);
  492.  
  493.     for(i=strlen(buf); i >= 0 && buf[i] != '/'; --i)
  494.     ;
  495.     return &buf[++i];
  496. }
  497.  
  498. /* Returns a pointer to the full filename (real order) ONLY FOR play_list! */
  499.  
  500. char *get_fullmodulename_ptr(int nr)
  501. {
  502.     return av[songs[nr]];
  503. }
  504.  
  505.  
  506. void init_playsequence(void)
  507. {
  508.     int i, j, n;
  509.     
  510.     for(i=0; i < nr_songs; ++i)
  511.     song_sequence[i]=-1;
  512.     
  513.     for(i=0; i < nr_songs; ++i) {
  514.     if(default_opt.random_mode) {
  515.         n=rand()%(nr_songs-i);
  516.         for(j=0; n >= 0; ++j)
  517.         if(song_sequence[j] < 0)
  518.             --n;
  519.         song_sequence[--j]=i;
  520.     }
  521.     else {
  522.         song_sequence[i]=i;
  523.     }
  524.     }
  525. }
  526.  
  527.  
  528. int fileidx_to_seqidx(int nr)
  529. {
  530.     int i;
  531.     
  532.     if(opt.play_list) { /* song_sequence not used when there is no play_list */
  533.     for(i=0; ; ++i) {
  534.         if(song_sequence[i] == nr) {
  535.         nr=i;
  536.         break;
  537.         }
  538.     }
  539.     }
  540.     return nr;
  541. }
  542.  
  543.  
  544. int seqidx_to_fileidx(int nr)
  545. {
  546.     return song_sequence[nr];
  547. }
  548.